
from ctypes import *
from common_c import load_library

libxp3 = load_library('libxp3')
libxp3_fate = load_library('libxp3_fate')

class xp3_segment_t(Structure):
	_fields_ = (('compressed',  c_int32),
	            ('offset', c_int64),
	            ('original_size', c_int64),
	            ('compressed_size', c_int64))

class xp3_entry_t(Structure):
	_fields_ = (('encrypted',  c_int32),
	            ('original_size', c_int64),
	            ('compressed_size', c_int64),
	            ('name_len', c_int16),
	            ('name', POINTER(c_wchar)),
	            ('segment_number', c_int32),
	            ('segments', POINTER(xp3_segment_t)),
	            ('adlr', c_int32))
class xp3_entries_t(Structure):
	_fields_ = (('entry_number',  c_int32),
	            ('entries', POINTER(xp3_entry_t)))

def read_xp3_indexes(path):
	if isinstance(path, unicode):
		import sys
		path = path.encode(sys.getfilesystemencoding())
	index = cast(libxp3.read_xp3_indexes(path), POINTER(xp3_entries_t))
	assert index
	return index

def free_xp3_indexes(indexes):
	libxp3.free_xp3_indexes(indexes)

fate_decrypter = libxp3_fate.xp3_fate_decrypter

def entry_name(entry):
	return wstring_at(entry.name, entry.name_len)

def decode_entry(path, entry, decrypter=libxp3_fate.xp3_fate_decrypter):
	if isinstance(path, unicode):
		import sys
		path = path.encode(sys.getfilesystemencoding())
	buffer = create_string_buffer(entry.original_size)
	n = libxp3.decode_xp3_entry_in_buffer(path, byref(entry), buffer, decrypter)
	if n:
		raise RuntimeError('decode_xp3_entry_in_buffer failed')
	return buffer.raw

from archive_base import Entry

class XP3Entry(Entry):
	def __init__(self, indexes, i):
		self.indexes = indexes
		c_entry = indexes.entries[i]
		self.c_entry = c_entry
		self.name = entry_name(c_entry)
		self.size = c_entry.original_size
		self.c_entry = c_entry
	def decode(self):
		return decode_entry(self.indexes.path, self.c_entry, fate_decrypter)

class XP3Index:
	class XP3Iterator:
		def __init__(self, indexes):
			self._indexes = None
			self._indexes = indexes
			self._i = 0
		def next(self):
			if self._i >= self._indexes.n:
				raise StopIteration
			i = self._i
			self._i += 1
			return XP3Entry(self._indexes, i)

	def __init__(self, path):
		self.path = path
		self.index = read_xp3_indexes(path)
		self.entries = self.index.contents.entries
		self.n = self.index.contents.entry_number

	def __del__(self):
		free_xp3_indexes(self.index)

	def __iter__(self):
		return XP3Index.XP3Iterator(self)


class XP3Reader:
	def __init__(self, path):
		self.path = path
		indexes = XP3Index(path)
		self.entries = indexes

if __name__ == '__main__':
	def print_shift(x):
		print x.decode('shift-jis').encode('gbk', 'ignore')

	entries = XP3Reader('patch.xp3').entries
	print_shift(list(entries)[0].decode())




